package com.example.im.ui.activity

import android.annotation.SuppressLint
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.content.Intent
import android.content.pm.ActivityInfo
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.text.Editable
import android.text.TextWatcher
import android.view.*
import android.widget.*
import androidx.appcompat.app.AlertDialog
import androidx.recyclerview.widget.*
import cn.dreamtobe.kpswitch.util.KPSwitchConflictUtil
import cn.dreamtobe.kpswitch.util.KeyboardUtil
import com.example.im.BuildConfig
import com.example.im.common.Enumerate
import com.example.im.R
import com.example.im.common.ImApplication
import com.example.im.entity.*
import com.example.im.common.Constants
import com.example.im.mvp.presenter.ChatPresenter
import com.example.im.mvp.view.IChatView
import com.example.im.ui.abstracts.AbstractBaseActivity
import com.example.im.ui.adapter.ChatAdapter
import com.example.im.ui.adapter.ChatEmojiAdapter
import com.example.im.ui.custom.MyImageLoader
import com.example.im.ui.custom.RecordButton
import com.example.im.ui.custom.VoiceTextView
import com.example.im.utils.JsonUtils
import com.previewlibrary.GPreviewBuilder
import com.previewlibrary.ZoomMediaLoader
import com.zhihu.matisse.Matisse
import com.zhihu.matisse.MimeType
import com.zhihu.matisse.engine.impl.GlideEngine
import com.zhihu.matisse.internal.entity.CaptureStrategy
import kotlinx.android.synthetic.main.activity_chat.*
import kotlinx.android.synthetic.main.include_toolbar.*
import kotlinx.android.synthetic.main.linear_item_chat_voice.view.*
import me.rosuh.filepicker.config.FilePickerManager
import org.greenrobot.eventbus.EventBus
import kotlinx.android.synthetic.main.popup_chat_item_long.view.*
import org.jivesoftware.smack.packet.Message


class ChatActivity : AbstractBaseActivity<ChatPresenter>(), IChatView, TextWatcher,
    View.OnKeyListener, RecordButton.OnFinishedRecordListener,
    CompoundButton.OnCheckedChangeListener, ChatAdapter.OnClickItemListener {

    companion object {
        private const val REQUEST_CODE_PHOTO = 1
        private const val REQUEST_CODE_VIDEO = 2
        private const val REQUEST_CODE_FILES = 3
        private const val REQUEST_CODE_RELAY = 4
        private val numbers = mutableListOf(
            0x1F601, 0x1F602, 0x1F603, 0x1F604, 0x1F605, 0x1F606, 0x1F609, 0x1F60A,
            0x1F60B, 0x1F60C, 0x1F60D, 0x1F60F, 0x1F612, 0x1F613, 0x1F614, 0x1F616,
            0x1F618, 0x1F61A, 0x1F61C, 0x1F61D, 0x1F61E, 0x1F620, 0x1F621, 0x1F622,
            0x1F623, 0x1F624, 0x1F625, 0x1F628, 0x1F629, 0x1F62A, 0x1F62B, 0x1F62D,
            0x1F630, 0x1F631, 0x1F632, 0x1F633, 0x1F635, 0x1F637, 0x1F638, 0x1F639,
            0x1F63A, 0x1F63B, 0x1F63C, 0x1F63D, 0x1F63E, 0x1F63F, 0x1F640, 0x1F645,
            0x1F646, 0x1F647, 0x1F648, 0x1F649, 0x1F64A, 0x1F64B, 0x1F64C, 0x1F64D,
            0x1F64E, 0x1F64F
        )
    }

    private var isApplyPermissions: Boolean = false

    private var mFriendOrRoom = FriendOrRoom()

    private var mEntire = mutableListOf<ChatRecordEntire>()
    private var adapter: ChatAdapter? = null

    override val layoutId: Int
        get() = R.layout.activity_chat

    override fun initView() {
        supportActionBar?.setDisplayHomeAsUpEnabled(true)

        mFriendOrRoom = intent.getSerializableExtra(Constants.BUNDLE_T0_CHAT_DATA) as FriendOrRoom

        tv_toolbar_title.text = mFriendOrRoom.nickname

        //更新数据库状态
        ImApplication.appDatabase().chatRecordEntireDao()
            .upDateChatRecordEntireStatus(0, 1, mFriendOrRoom.id)

        //获取聊天记录
        mEntire = ImApplication.appDatabase().chatRecordEntireDao()
            .selectChatRecordEntire(mFriendOrRoom.id)

        //初始化并默认加载聊天记录
        adapter = ChatAdapter((this), mEntire, mFriendOrRoom.type)
        adapter!!.setOnClickItemListener(this)
        val layoutManager1 = LinearLayoutManager(this)
        layoutManager1.stackFromEnd = true
        recycler_view_chat.layoutManager = layoutManager1
        recycler_view_chat.adapter = adapter


        //初始化并默认加载表情
        val adapter = ChatEmojiAdapter((this), numbers)
        adapter.setOnItemClickListener { _, i ->
            edit_chat_content.text.insert(
                edit_chat_content.selectionStart,
                String(Character.toChars(numbers[i]))
            )
        }
        val layoutManager2 = GridLayoutManager(this, 7)
        layoutManager2.orientation = GridLayoutManager.VERTICAL
        recycler_view_emoji.layoutManager = layoutManager2
        recycler_view_emoji.adapter = adapter

        text_chat_voice.setOnFinishedRecordListener(this)
        btn_chat_voice.setOnCheckedChangeListener(this)
        btn_chat_emoji.setOnCheckedChangeListener(this)
        edit_chat_content.addTextChangedListener(this)
        edit_chat_content.setOnKeyListener(this)

        KeyboardUtil.attach(this, panel_root) {
            if (it) btn_chat_emoji.isChecked = false
        }
        KPSwitchConflictUtil.attach(
            panel_root, btn_chat_emoji, edit_chat_content
        ) {
            if (it) btn_chat_voice.isChecked = false
        }
    }

    override fun initPresenter() {
        mPresenter = ChatPresenter((this), (this))
    }

    override fun onStart() {
        super.onStart()
        mPresenter!!.chatApplyPermissions(this)
    }

    override fun onStop() {
        super.onStop()
        if (mVoiceTextView != null) {
            mVoiceTextView!!.stopPlay()
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        //关闭时通知聊天列表更新条目
        val last = ImApplication.appDatabase().chatRecordLastDao()
            .selectChatRecordLastByFId(mFriendOrRoom.id)
            ?: return
        val busData = EventBusData(
            Enumerate.Handle.list_chat, Enumerate.Action.list_updata, last
        )
        EventBus.getDefault().post(busData)
    }

    override fun dispatchKeyEvent(event: KeyEvent): Boolean {
        if (event.action == KeyEvent.ACTION_UP && event.keyCode == KeyEvent.KEYCODE_BACK) {
            if (panel_root.visibility == View.VISIBLE) {
                btn_chat_emoji.isChecked = false
                KPSwitchConflictUtil.hidePanelAndKeyboard(panel_root)
                return true
            }
        }
        return super.dispatchKeyEvent(event)
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        if (resultCode != RESULT_OK)
            return
        val paths = when (requestCode) {
            REQUEST_CODE_PHOTO -> Matisse.obtainPathResult(data)
            REQUEST_CODE_VIDEO -> data!!.getStringArrayListExtra(Constants.BUNDLE_VIDEO_PATH)
            REQUEST_CODE_FILES -> FilePickerManager.obtainData()
            else -> ArrayList()
        }
        if (requestCode == REQUEST_CODE_RELAY) {
            val friendOrRoom = (data?.getSerializableExtra("FRIEND_OR_ROOM") as FriendOrRoom)
            val chatContent = (data.getSerializableExtra("CHAT_CONTENT") as ChatContent)
            mPresenter!!.setInitUserAndType(
                friendOrRoom.account!!, if (friendOrRoom.type == Message.Type.chat.ordinal)
                    Message.Type.chat else Message.Type.groupchat
            )
            mPresenter!!.chatSendRelay(chatContent)
        } else {
            if (paths.isEmpty()) {
                return
            }
            mPresenter!!.setInitUserAndType(
                mFriendOrRoom.account!!, if (mFriendOrRoom.type == Message.Type.chat.ordinal)
                    Message.Type.chat else Message.Type.groupchat
            )
            mPresenter!!.chatSendFile(paths)
        }

    }

    override fun onEventMainThread(eventBus: EventBusData<*>) {
        super.onEventMainThread(eventBus)
        if (eventBus.type ?: return != Enumerate.Handle.list_chat)
            return
        when (eventBus.action ?: return) {
            Enumerate.Action.list_add -> {
                val data = eventBus.data ?: return
                if (data is MutableMap.MutableEntry<*, *>) {
                    val last = data.key as ChatRecordLast
                    if (last.fId != mFriendOrRoom.id)
                        return
                    val entire = data.value as ChatRecordEntire
                    recycler_view_chat.layoutManager!!
                        .scrollToPosition(adapter!!.itemCount)
                    adapter!!.addDataItem(entire)
                }
            }
            Enumerate.Action.list_delete -> {
                adapter!!.clearData()
            }
            else -> {
            }
        }
    }

    override fun onCreateOptionsMenu(menu: Menu?): Boolean {
        menuInflater.inflate(R.menu.top_nav_menu_chat, menu)
        return true
    }

    override fun onOptionsItemSelected(item: MenuItem?): Boolean {
        when (item?.itemId) {
            android.R.id.home -> {
                onBackPressed()
            }
            R.id.action_info -> {

                val intent = Intent()
                if (mFriendOrRoom.type == Message.Type.chat.ordinal) {
                    intent.setClass(this, UserActivity::class.java)
                    intent.putExtra(Constants.BUNDLE_T0_USER_DATA, mFriendOrRoom)
                } else {
                    intent.setClass(this, RoomActivity::class.java)
                    intent.putExtra(
                        Constants.BUNDLE_T0_ROOM_MARK,
                        Constants.BUNDLE_T0_ROOM_MARK_CENTRE
                    )
                    intent.putExtra(Constants.BUNDLE_T0_ROOM_DATA, mFriendOrRoom)
                }
                startActivity(intent)
            }
        }
        return super.onOptionsItemSelected(item)
    }


    /**
     * 录音结束返回地址
     * */
    @SuppressLint("Recycle")
    override fun onFinishedRecord(audioPath: String?) {
        mPresenter!!.setInitUserAndType(
            mFriendOrRoom.account!!, if (mFriendOrRoom.type == Message.Type.chat.ordinal)
                Message.Type.chat else Message.Type.groupchat
        )
        mPresenter!!.chatSendFile(arrayListOf(audioPath!!))
    }


    /**
     * 选择语音、表情点击事件
     * */
    override fun onCheckedChanged(buttonView: CompoundButton?, isChecked: Boolean) {
        when (buttonView!!.id) {
            R.id.btn_chat_voice -> {
                if (isChecked) {
                    KPSwitchConflictUtil.hidePanelAndKeyboard(panel_root)
                    ll_content.visibility = View.GONE
                    ll_voice.visibility = View.VISIBLE
                    btn_chat_emoji.isChecked = false
                } else {
                    ll_content.visibility = View.VISIBLE
                    ll_voice.visibility = View.GONE
                }
            }
        }
    }


    /**
     * 内容输入框监听-更改后文本
     * */
    override fun afterTextChanged(s: Editable?) {
        if (s!!.isNotEmpty()) {
            text_chat_send.setBackgroundResource(R.drawable.style_chat_text_send_light)
        } else {
            text_chat_send.setBackgroundResource(R.drawable.style_chat_text_send)
        }
    }

    /**
     * 内容输入框监听-更改前文本
     * */
    override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
    }

    /**
     * 内容输入框监听-正在修改文本
     * */
    override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {

    }

    /**
     * 软键盘删除键监听
     * */
    override fun onKey(v: View?, keyCode: Int, event: KeyEvent?): Boolean {

        if (keyCode == KeyEvent.KEYCODE_DEL && event!!.action == KeyEvent.ACTION_DOWN) {
            val text = edit_chat_content.text
            if (text.lastIndexOf("\u2005") != -1 &&
                edit_chat_content.selectionStart - text.lastIndexOf("\u2005") == 1
            ) {
                edit_chat_content.text.delete(
                    text.lastIndexOf("@"), text.lastIndexOf("\u2005")
                )
            }
        }
        return false
    }

    /******************************列表条目item点击事件**********************************/


    override fun onClickItemChatHeard(v: View, position: Int) {

    }

    /**
     * 聊天条目重发事件
     * */
    override fun onClickItemChatRelay(v: View, position: Int) {
        mPresenter!!.setInitUserAndType(
            mFriendOrRoom.account!!, if (mFriendOrRoom.type == Message.Type.chat.ordinal)
                Message.Type.chat else Message.Type.groupchat
        )
        mPresenter!!.chatSendRepeat(mEntire[position])
    }

    /**
     * 聊天条目长按事件（头像）
     * */
    override fun onClickItemChatLong(v: View, position: Int) {
        val from = mEntire[position].from
            ?: return
        val user = from.substring(from.indexOf("/") + 1, from.length)
        edit_chat_content.text.insert(
            edit_chat_content.selectionStart, "@$user\u2005"
        )
    }

    /**
     * 内容条目语音点击事件
     * */
    override fun onClickItemContentVoice(v: View, position: Int) {
        mPresenter!!.chatReceiveVoice(v, mEntire[position])
    }

    /**
     * 内容条目图片点击事件
     * */
    override fun onClickItemContentPhoto(v: View, position: Int) {

        ZoomMediaLoader.getInstance().init(MyImageLoader())

        val content = JsonUtils.stringToObject(
            mEntire[position].body, ChatContent::class.java
        )
        val url = content.fileInfo!!.localUrl
            ?: content.fileInfo!!.netUrl
        GPreviewBuilder.from(this)//activity实例必须
            .setData(arrayListOf(ThumbView(url)))//集合
            .setCurrentIndex(0)
            .setSingleFling(false)//是否在黑屏区域点击返回
            .setDrag(false)//是否禁用图片拖拽返回
            .setType(GPreviewBuilder.IndicatorType.Dot)//指示器类型
            .start()//启动
    }

    /**
     * 内容条目文件点击事件
     * */
    override fun onClickItemContentFiles(v: View, position: Int) {


        val chatRecordEntire = ImApplication.appDatabase!!.chatRecordEntireDao()
            .getChatRecordEntireByID(mEntire[position].id)

        val content = JsonUtils.stringToObject(
            chatRecordEntire.body, ChatContent::class.java
        )

        if (!content.fileInfo!!.localUrl.isNullOrEmpty()) {
            val dialog = AlertDialog.Builder(this)
                .setMessage("文件已下载，保存路劲：${content.fileInfo!!.localUrl}")
                .setPositiveButton("确定") { d, _ ->
                    d.cancel()
                }
            dialog.show()
        } else {
            val dialog = AlertDialog.Builder(this)
                .setTitle("下载文件")
                .setMessage(content.fileInfo!!.name)
                .setPositiveButton("下载") { d, _ ->
                    d.cancel()
                    mPresenter!!.chatDownloadFiles(chatRecordEntire)
                }
                .setNegativeButton("取消", null)
            dialog.show()
        }
    }

    /**
     * 内容条目长按事件
     * */
    override fun onClickItemContentLong(v: View, position: Int) {
        val entire = mEntire[position]

        val content = JsonUtils.stringToObject(
            entire.body, ChatContent::class.java
        )

        val view = LayoutInflater.from(this)
            .inflate(R.layout.popup_chat_item_long, null, false)

        if (content.type == Constants.CONTENT_TYPE_TEXT) {
            view.tv_popup_item_copy.visibility = View.VISIBLE
            view.view_popup_item_line.visibility = View.VISIBLE
        } else {
            view.tv_popup_item_copy.visibility = View.GONE
            view.view_popup_item_line.visibility = View.GONE
            view.tv_popup_item_delete.setBackgroundResource(R.drawable.style_chat_popup_long_copy)
        }
        view.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED)

        val window = PopupWindow(
            view, LinearLayout.LayoutParams.WRAP_CONTENT,
            LinearLayout.LayoutParams.WRAP_CONTENT, true
        )
        window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
        window.isOutsideTouchable = true
        window.isTouchable = true
        window.showAsDropDown(
            v, if (entire.or == Constants.CHAT_SEND) {
                -view.measuredWidth
            } else 0,
            -v.height - (view.measuredHeight / 2),
            if (entire.or == Constants.CHAT_SEND) {
                Gravity.END
            } else Gravity.START
        )
        view.tv_popup_item_copy.setOnClickListener {
            window.dismiss()
            val cm = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
            val cd = ClipData.newPlainText("Label", content.body)
            cm.primaryClip = cd
        }
        view.tv_popup_item_delete.setOnClickListener {
            window.dismiss()
            ImApplication.appDatabase()
                .chatRecordEntireDao().delete(entire)
            adapter!!.removeDataItem(position)
        }
        view.tv_popup_item_relay.setOnClickListener {
            window.dismiss()
            if (entire.status == 2 || entire.status == 3) {
                onHint("发送失败的消息不可转发！")
                return@setOnClickListener
            }
            val intent = Intent(this, SearchActivity::class.java)
            intent.putExtra(Constants.BUNDLE_T0_SEARCH_DATA, content)
            startActivityForResult(intent, REQUEST_CODE_RELAY)
        }
    }


    /******************************聊天页面控件单击事件监听**********************************/
    /**
     * 输入框的点击事件
     * */
    fun onClickEventContent(v: View) {
        val cursor = edit_chat_content.selectionStart
        val frontText = edit_chat_content.text.substring(0, cursor)
        val afterText = edit_chat_content.text.substring(cursor)
        val atIndex = if ((frontText.lastIndexOf("@") > frontText.lastIndexOf("\u2005"))
            || frontText.lastIndexOf("\u2005") == -1
        ) {
            frontText.lastIndexOf("@")
        } else -1

        val bsIndex = if ((afterText.indexOf("\u2005") < afterText.indexOf("@"))
            || afterText.indexOf("@") == -1
        ) {
            afterText.indexOf("\u2005")
        } else -1

        if (atIndex != -1 && bsIndex != -1) {
            edit_chat_content.setSelection(atIndex, cursor + bsIndex + 1)
        }
    }

    /**
     * 发送点击事件
     * */
    fun onClickEventSend(v: View) {
        val content = edit_chat_content.text.toString()
        val arrayText = HashSet<String>()
        var text = content
        while (text.indexOf("@") != -1 && text.indexOf("\u2005") != -1) {
            arrayText.add(text.substring(text.indexOf("@") + 1, text.indexOf("\u2005")))
            text = text.substring(text.indexOf("\u2005") + 1, text.length)
        }
        mPresenter!!.setInitUserAndType(
            mFriendOrRoom.account!!, if (mFriendOrRoom.type == Message.Type.chat.ordinal)
                Message.Type.chat else Message.Type.groupchat
        )
        mPresenter!!.chatSendText(content, arrayText)
        edit_chat_content.text = null
    }

    /**
     * 视频拍摄点击事件
     * */
    fun onClickEventVideo(v: View) {
        onHint("该功能未实现！")
    }

    /**
     * 图片选择点击事件
     * */
    fun onClickEventPhoto(v: View) {

        Matisse.from(this)
            .choose(MimeType.ofImage())
            .showSingleMediaType(true)
            .capture(true)
            .captureStrategy(
                CaptureStrategy(
                    true, "${BuildConfig.APPLICATION_ID}.file_provider"
                )
            )
            .countable(true)
            .maxSelectable(9)
            .restrictOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
            .thumbnailScale(0.8f)
            .theme(R.style.Matisse_Dracula_1)
            .imageEngine(GlideEngine())
            .forResult(REQUEST_CODE_PHOTO)
    }

    /**
     * 文件选择点击事件
     * */
    fun onClickEventFiles(v: View) {
        FilePickerManager
            .from(this)
            .maxSelectable(9)
            .setTheme(R.style.FilePickerThemeRail_1)
            .forResult(REQUEST_CODE_FILES)
    }


    /******************************Presenter返回监听**********************************/

    /**
     * 返回权限是否同意监听事件
     * */
    override fun isPermissionsPresenter(isApply: Boolean) {
        isApplyPermissions = isApply
    }

    /**
     * 返回语音播放链接监听事件
     * */
    private var mVoiceTextView: VoiceTextView? = null

    override fun onVoicePathPresenter(view: View, path: String) {
        if (mVoiceTextView != null && mVoiceTextView!!.tag != view.tv_chat_item_voice.tag) {
            mVoiceTextView!!.stopPlay()
        }
        view.tv_chat_item_voice.startPlay(path)
        mVoiceTextView = view.tv_chat_item_voice
    }

}